#include "Connection.hpp"
#include "Epoller.hpp"

namespace EpollModule
{
    using func_t  = function<string(string&)>;

    class IOService : public Connection
    {
    private:
        func_t _handle_message;
    public:
        IOService(int fd)
        {
            SetSocketFd(fd);
            SetEvent(EPOLLIN | EPOLLET);
            SetNoBlock(fd); //设置非阻塞读
        }

        void RegisterHandle(func_t handle)
        {
            _handle_message = handle;
        }

        virtual void Sender() override
        {
            //对于发送条件，我们一直认为都是就绪的
            //直接发，发失败了，就托管给epoll
            while(true)
            {
                size_t n = write(_sockfd,_outbuffer.c_str(),_outbuffer.size());
                if(n > 0)
                {
                    //此次发送成功，将已发送的数据从用户缓冲区移除,移除n个
                    RemoveFromOutBuffer(n); 
                }
                else if(n == 0)
                {
                    break;  //我们认为发送完了
                }
                else
                {
                    if(errno == EAGAIN || errno == EWOULDBLOCK)
                    {
                        //此时，内核发送缓冲区已满，下次再来
                        break;
                    }
                    else if(errno == EINTR)
                    {
                        continue;
                    }
                    else
                    {
                        Excepter();
                        return;
                    }
                }
            }

            //此时，如果用户发送缓冲区还有数据，说明内核缓冲区满了，需要将fd托管给epoll
            if(!OutBufferIsEmpty())
            {
                //关心当前fd的写事件
                GetOwner()->EnableReadOrWrite(_sockfd,true,true);
            }
            else
            {
                //关闭写事件
                GetOwner()->EnableReadOrWrite(_sockfd,true,false);
            }
        }

        virtual void Recver() override
        {
            //此时，一定可以读了，不会阻塞
            while(true)
            {
                char buff[1024];
                int len = recv(_sockfd,buff,sizeof(buff) - 1,0);
                //读取成功
                if(len > 0)
                {
                    buff[len] = 0;
                    //添加到用户层的读缓冲区
                    InputBufAppend(buff);
                }
                else if(len == 0)
                {
                    //对端关闭连接
                    Excepter();
                    break;
                }
                else
                {
                    if(errno == EAGAIN || errno == EWOULDBLOCK)
                    {
                        //读完了
                        break;
                    }
                    else if(errno == EINTR)
                    {
                        continue;
                    }
                    else
                    {
                        //错误
                        Excepter();
                        return;
                    }
                }
            }
            //来到这里，一定将内核缓冲区的数据读完了
            // cout << "inbuff:" << _inbuffer << endl;
            //但是，你能确定这个报文是完整的吗？-- 不能，必须通过"协议"判断
            string result;
            if(_handle_message)
                result = _handle_message(_inbuffer);    //将读到的数据交给上层处理

            //处理结果放到outbuffer中
            OuputBufAppend(result.c_str());

            //有数据要发
            if(!OutBufferIsEmpty())
            {
                //方案1: 
                //Sender(); //直接发送即可
                
                //方案2：
                //使该fd关心写事件。写事件就绪，会直接调用sender发送
                GetOwner()->EnableReadOrWrite(_sockfd,true,true);
            }
        }

        virtual void Excepter() override
        {
            LOG(LogGrade::ERROR) << "客户端连接可能结束，进行异常处理: " << _sockfd;
            //出现了异常，我们什么也做不了，只能从epll中移除，关闭连接
            GetOwner()->DelConnection(_sockfd);
        }
    };
}
